/**
 * 
 */
package com.mnurre.shopping.assistant;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.SimpleCursorAdapter;

/**
 * @author michael
 * See the tutorial here: http://www.androidhive.info/2012/01/android-json-parsing-tutorial/
 */
public class ManageProductsActivity extends ListActivity {

	private static final String TAG = "ManageProductsActivity";
	
	private static final String GOOGLE_SHOPPER_API = "https://www.googleapis.com/shopping/search/v1/public/products?";
	private static final String API_KEY = "AIzaSyCJz3TBnJ2DmA5pdmVZtRGQAl8R-rKi-Uo";

	private ProductsData mData;
	private ListsData mListsData;
	private Cursor mCursor;
	
	private static final int PRODUCT_ADD = 0;
	private static final int PRODUCT_EDIT = 1;
	private static final int PRODUCT_ADD_BY_SCAN = 2;
	
	private Long mListId;
	
	/* (non-Javadoc)
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		Log.d(TAG, "Creating activity.");
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_manage_products);
		
		Log.d(TAG, "Populating the products.");
		populateProducts();
		
		Log.d(TAG, "Registering for context menu.");
		registerForContextMenu(getListView());
		
		Log.d(TAG, "Checking to see if we are selecting a product from the edit list activity.");
		Bundle extras = getIntent().getExtras();
		if(extras != null){
			Log.d(TAG, "We are adding a product from a list. Getting list id.");
			mListId = extras.getLong(DataManager.Tables.Lists.COLUMN_ID);
			Log.d(TAG, "List Id is " + mListId);
			setTitle(R.string.product_add_to_list_activity_label);
		}
	}
	
	/* (non-Javadoc)
	 * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		Log.d(TAG, "Creating options menu.");
		super.onCreateOptionsMenu(menu);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu_manage, menu);
		Log.d(TAG, "Done creating options menu.");
		return true;
	}
	
	/* (non-Javadoc)
	 * @see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)
	 */
	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo menuInfo) {
		// TODO Check mListId to see if we are adding from a list
		Log.d(TAG, "Creating context menu.");
		super.onCreateContextMenu(menu, v, menuInfo);
		MenuInflater inflater = getMenuInflater();
		if(mListId == null){
			inflater.inflate(R.menu.menu_manage_context, menu);
		} else {
			inflater.inflate(R.menu.menu_context_edit_list_add_product, menu);
		}
		Log.d(TAG, "Done creating context menu.");
	}

	/* (non-Javadoc)
	 * @see android.app.Activity#onMenuItemSelected(int, android.view.MenuItem)
	 */
	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		// TODO Auto-generated method stub
		switch(item.getItemId()){
		case R.id.menu_manage_add:
			Log.d(TAG, "The add menu was selected. Starting intext to scan product.");
			// use the onActivityResult to manage results
			try{
				IntentIntegrator integrator = new IntentIntegrator(this);
				AlertDialog dialog = integrator.initiateScan();
				if(dialog != null) {
					// they did not have barcode scanner installed.
					// prompting them to install. In the meantime, open
					// the edit product activity
					Intent intent = new Intent(this, EditProductActivity.class);
					startActivityForResult(intent, PRODUCT_ADD);
				}
			} catch(Exception ex){
				ex.printStackTrace();
				return false;
			}
			break;
		}
		return super.onMenuItemSelected(featureId, item);
	}
	
	/* (non-Javadoc)
	 * @see android.app.Activity#onContextItemSelected(android.view.MenuItem)
	 */
	@Override
	public boolean onContextItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		Log.d(TAG, "Context menu item selected.");
		AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
		switch(item.getItemId()){
		case R.id.manage_menu_context_option_delete:
			// TODO verify they want to delete because it will
			// remove it from all lists
			Log.d(TAG, "Delete context menu selected.");
			mData.open();
			mData.deleteProduct(info.id);
			mData.close();
			populateProducts();
			break;
		case R.id.manage_menu_context_option_edit:
			Log.d(TAG, "Edit context menu selected.");
			Intent intent = new Intent(this, EditProductActivity.class);
			intent.putExtra(DataManager.Tables.Products.COLUMN_ID, info.id);
			startActivityForResult(intent, PRODUCT_EDIT);
			Log.d(TAG, "Done launching activity to edit product.");
			break;
		case R.id.menu_manage_select:
			Log.d(TAG, "Select context menu selected.");
			// TODO update the ProductsByList table with the selected product
			// for the list and return success
			long selectedProductId = info.id;
			Log.d(TAG, "Adding selected product id of " + selectedProductId + " to list with id of " + mListId);
			mListsData = new ListsData(this);
			Log.d(TAG, "Opening lists data and adding product.");
			mListsData.open();
			mListsData.addProductToListByProductId(mListId, selectedProductId);
			Log.d(TAG, "Closing list data and setting result.");
			mListsData.close();
			setResult(RESULT_OK);
			finish();
			break;
		}
		Log.d(TAG, "Returning super.onContextItemSelected.");
		return super.onContextItemSelected(item);
	}
	
	/* (non-Javadoc)
	 * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		// super.onActivityResult(requestCode, resultCode, data);
		if(requestCode == PRODUCT_ADD || requestCode == PRODUCT_EDIT){
			Log.d(TAG, "We are ending an add or edit activity. Calling populating products.");
			populateProducts();
		} else {
			Log.d(TAG, "Scanning for the barcode. Calling IntentIntegrator.parseActivityResult.");
			IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
			Log.d(TAG, "Checking the results of the scan.");
			if(scanResult != null){
				 Log.d(TAG, "We have scan results.");
				// call google shopping api to determine what the product is
				// then call the EditProductActivity with the data
//				try {
				 Log.d(TAG, "Getting barcode.");
					String barcode = scanResult.getContents();
					Log.d(TAG, "Barcode = " + barcode);
					Log.d(TAG, "Calling getProductFromBarcode");
					Product product = getProductFromBarcode(barcode);
					if(product != null){
						Intent intent = new Intent(this, EditProductActivity.class);
						intent.putExtra(DataManager.Tables.Products.COLUMN_CATEGORY, product.getCategory());
						intent.putExtra(DataManager.Tables.Products.COLUMN_DESCRIPTION, product.getDescripition());
						intent.putExtra(DataManager.Tables.Products.COLUMN_NAME, product.getName());
						intent.putExtra(DataManager.Tables.Products.COLUMN_BARCODE, barcode);
						startActivityForResult(intent, PRODUCT_EDIT);
					} else {
						// process of scanning was canceled or we got an error
						Log.d(TAG, "Bringing up edit with no scan data.");
						Intent intent = new Intent(this, EditProductActivity.class);
						startActivityForResult(intent, PRODUCT_ADD);
					}
					
//				} catch (JSONException e) {
//					// TODO Auto-generated catch block
//					showErrorMessage(e);
//				}
			} else {
				// process of scanning was canceled. Load the edit products like normal.
				Intent intent = new Intent(this, EditProductActivity.class);
				startActivityForResult(intent, PRODUCT_ADD);
			}
		}
	}

	private void populateProducts() {
		Log.d(TAG, "Populate products called.");
		Log.d(TAG, "Creating a new instance of ProductsData.");
		mData = new ProductsData(this);
		Log.d(TAG, "Opening data and getting cursor for all products.");
		mData.open();
		mCursor = mData.getAllProducts();
		Log.d(TAG, "Calling startManagingCursor.");
		startManagingCursor(mCursor);
		Log.d(TAG, "Creating from array.");
		String[] from = new String[] { DataManager.Tables.Products.COLUMN_CATEGORY, 
				DataManager.Tables.Products.COLUMN_NAME, 
				DataManager.Tables.Products.COLUMN_DESCRIPTION,
				DataManager.Tables.Products.COLUMN_PRICE };
		Log.d(TAG, "Creating to array.");
		int[] to = new int[] { R.id.productItemCategoryTextView, 
				R.id.productItemNameTextView, 
				R.id.productItemDescriptionTextView,
				R.id.productItemPriceTextView };
		Log.d(TAG, "Creating a new SimpleCursorAdapter.");
		SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.product_item_table_layout, mCursor, from, to);
		Log.d(TAG, "Calling setListAdapter.");
		setListAdapter(adapter);
		Log.d(TAG, "Done setting adapter.");
		Log.d(TAG, "Closing database connection.");
		mData.close();
	}
	
	/*
	 * Gets the product data from google shopping api with the product barcode.
	 * This will start the EditProductsActivity will all data populated but the price.
	 * http://stackoverflow.com/questions/9968114/android-sending-https-get-request
	 * http://stackoverflow.com/questions/9383526/android-json-parsing-from-google-shopping-api-error
	 * example call for products
	 * https://www.googleapis.com/shopping/search/v1/public/products?key={my google key}&country=US&gtin={barcode}&alt=atom
	 * This needs to be run by an AsyncTask
	 */
	private Product getProductFromBarcode(String barcode) {
		Log.d(TAG, "getProductFromBarcode called.");
			HttpResponse response = null;
			Product product = null;
			try {        
					Log.d(TAG, "Getting the default http client.");
			        HttpClient client = new DefaultHttpClient();
			        Log.d(TAG, "Getting an http get.");
			        HttpGet request = new HttpGet();
			        Log.d(TAG, "Setting uri.");
			        request.setURI(new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=" + API_KEY + "&country=US&restrictBy=gtin:"+ barcode + "&alt=json"));
			        Log.d(TAG, "URI set to " + request.getURI());
			        Log.d(TAG, "Executing the request and waiting for response.");
			        response = client.execute(request);
			        Log.d(TAG, "Have resonse. Getting the text from the response stream.");
			        InputStream inputStream = null;
			        Writer writer = null;
			        try {
			        	Log.d(TAG, "Getting an inputStream with response.getEntity().getContents().");
				        inputStream = response.getEntity().getContent();
				        
				        Log.d(TAG, "Getting a new StringWriter for writing the data.");
				        writer = new StringWriter();
				        char[] buffer = new char[1024];
				        
				        Log.d(TAG, "Getting a BufferedReader and reading the data.");
				        Reader reader = new BufferedReader(new InputStreamReader(inputStream));
				        int n;
				        while((n = reader.read(buffer)) != -1){
				        	writer.write(buffer, 0, n);
				        }
				        Log.d(TAG, "Done reading data.");
			        } catch (Exception e) {
			        	throw e;
			        } finally {
			        	inputStream.close();
			        }
			        
			        Log.d(TAG, "Getting the json request.");
			        String jsonRequest = writer.toString();
			        Log.d(TAG, "RESPONSE:\n" + jsonRequest);
			        
			        Log.d(TAG, "Getting a json object and items array.");
					JSONObject jsonObject = new JSONObject(jsonRequest); // 
					JSONArray itemsArray = jsonObject.getJSONArray("items"); 
					JSONObject itemObject = itemsArray.getJSONObject(0); //
					
					Log.d(TAG, "Getting the product.");
					JSONObject productObject = itemObject.getJSONObject("product");
					String productTitle = productObject.has("title") ? productObject.getString("title") : "";
					
					Log.d(TAG, "Getting the description.");
					String description = productObject.has("description") ? productObject.getString("description").substring(0, 40) : "";
					// String brand = productObject.getString("brand");
					String category = productObject.has("categories") ? productObject.getString("categories") : "";
					
					product = new Product(productTitle, description, category, barcode);
			    } catch (URISyntaxException e) {
			    	Log.e(TAG, "Exception thrown when getting the product.\n" + e.getStackTrace());
			        showErrorMessage(e);
			    } catch (ClientProtocolException e) {
			        // TODO Auto-generated catch block
			    	Log.e(TAG, "Exception thrown when getting the product.\n" + e.getStackTrace());
			        showErrorMessage(e);
			    } catch (IOException e) {
			        // TODO Auto-generated catch block
			    	Log.e(TAG, "Exception thrown when getting the product.\n" + e.getStackTrace());
			        showErrorMessage(e);
			    } catch(Exception e){
			    	Log.e(TAG, "Exception thrown when getting the product.\n" + e.getStackTrace());
			    	showErrorMessage(e);
			    }
				return product;
			}
	
	private void showErrorMessage(Exception e){
		Log.e(TAG, "Building an error dialog for exception:\n" + e.getStackTrace());
		AlertDialog.Builder builder = new Builder(this);
		builder.setMessage(e.getMessage());
		builder.setTitle("Error in application.");
		builder.setCancelable(false);
		builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				return;
			}
		});
		builder.show();
	}
	
}


